package container;

import domain.User;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractRefreshableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.Environment;
import repository.UserRepository;

/**
 * 依赖注入
 * @author jackcfan
 * @date 2021/9/12
 */
public class DependencyInjection {
    @Before
    public void before(){

    }

    /**
     * 依赖查找 和 依赖注入 的源不同
     * */
    @Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("dependency-injection-context.xml");
        // 依赖来源一：自定义 Bean
        UserRepository userRepository = applicationContext.getBean("userRepository", UserRepository.class);

        // 依赖来源二：依赖注入（内建依赖）
        // userRepository 注入了 BeanFactory 对象
        System.out.println("依赖注入 BeanFactory:"+userRepository.getBeanFactory());

        // 依赖查找（报错）
        try{
            // 依赖查找 BeanFactory 报错，找不到这个 Bean
            BeanFactory beanFactory = applicationContext.getBean(BeanFactory.class);
        }catch (Exception e){
            System.out.println("BeanFactory 依赖查找失败");
        }
        System.out.println("UserCollection:"+userRepository.getUsers());

        // 依赖来源三：容器内建 Bean
        Environment environment = applicationContext.getBean(Environment.class);
        System.out.println(environment);

        /**
         * ClassPathXmlApplicationContext
         *      -> AbstractRefreshableApplicationContext
         *          -> ApplicationContext
         *              -> BeanFactory
         * ApplicationContext 实现了 BeanFactory，但是 ApplicationContext 并不是注入的 BeanFactory 对象
         * beanFactory != applicationContext
         * */
        System.out.println("beanFactory != applicationContext : "+(userRepository.getBeanFactory() != applicationContext));

        /**
         * ApplicationContext 间接继承了 AbstractRefreshableApplicationContext
         * AbstractRefreshableApplicationContext.getBeanFactory() -> DefaultListableBeanFactory
         * 返回了真正的 BeanFactory
         * 有点类似代理模式，AbstractRefreshableApplicationContext.getBeanFactory() 为代理对象
         * beanFactory == abstractContext.getBeanFactory()
         * */
        AbstractRefreshableApplicationContext abstractContext = (AbstractRefreshableApplicationContext) applicationContext;
        System.out.println("beanFactory == abstractContext : "+(userRepository.getBeanFactory() == abstractContext.getBeanFactory()));
    }

    /**
     * Spring 底层容器 BeanFactory
     * */
    @Test
    public void testDefaultListableBeanFactory(){
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        // 加载配置
        int loadBeanDefinitions = xmlBeanDefinitionReader.loadBeanDefinitions("dependency-lookup-context.xml");
        System.out.println("加载 BeanDefinition 数量:"+loadBeanDefinitions);

        User user = beanFactory.getBean(User.class);
        System.out.println("user:"+user);
    }
}
